package com.android.lovely.ui.viewmodel

import android.net.Uri
import androidx.lifecycle.viewModelScope
import com.android.lovely.R
import com.android.lovely.api.service.createRequestBodyFromUri
import com.android.lovely.api.service.fileName
import com.android.lovely.api.service.generateService
import com.android.lovely.api.service.taskService
import com.android.lovely.data.AiCreateEvent
import com.android.lovely.data.AiCreateState
import com.android.lovely.data.AiCreateUiEvent
import com.android.lovely.data.CreateImageDetail
import com.android.lovely.data.GeneratedModel
import com.android.lovely.data.ImageGenerateData
import com.android.lovely.data.ParamList
import com.android.lovely.framework.BaseViewModel
import com.android.lovely.framework.launchWithLoading
import com.android.lovely.user.UserManager
import com.kotlin.extensions.appContext
import com.kotlin.extensions.coroutine.CoroutineExt.launchSafety
import com.kotlin.extensions.json.JsonExt.toJson
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.Response

/**
 *
 * @author why
 * @date 2025/4/10 19:05
 */

class AiGenerateViewModel : BaseViewModel() {

    var createData: AiCreateState = AiCreateState()

    private val _createFlow = MutableSharedFlow<ImageGenerateData>(extraBufferCapacity = 1)
    val createFlow: SharedFlow<ImageGenerateData> = _createFlow

    private val _aiWrite = MutableSharedFlow<List<CreateImageDetail>>(extraBufferCapacity = 1)
    val aiWrite: SharedFlow<List<CreateImageDetail>> = _aiWrite

    private val _events = MutableSharedFlow<AiCreateEvent>()
    val events: SharedFlow<AiCreateEvent> = _events.asSharedFlow()

    private val _typeFlow = MutableStateFlow(0)
    val typeFlow: StateFlow<Int> = _typeFlow

    private val _genderFlow = MutableStateFlow(1)
    val genderFlow: StateFlow<Int> = _genderFlow

    private val _numFlow = MutableStateFlow(2)
    val numFlow: StateFlow<Int> = _numFlow

    private val _updateModel = MutableStateFlow(0)
    val updateModel: StateFlow<Int> = _updateModel

    private val _updateStyle = MutableStateFlow(0)
    val updateStyle: StateFlow<Int> = _updateStyle

    private val _updateNsfw = MutableStateFlow(false)
    val updateNsfw: StateFlow<Boolean> = _updateNsfw

    private val _textPictureMode = MutableStateFlow(false)
    val textPictureMode: StateFlow<Boolean> = _textPictureMode

//    private val _imgList = MutableSharedFlow<TaskImageDetail>(0)
//    val imgList: SharedFlow<TaskImageDetail> = _imgList

    init {
        loadAiCreateData()
    }

    fun onEvent(event: AiCreateUiEvent) {
        when (event) {
            is AiCreateUiEvent.OnTypeSelected -> updateType(event.type)
            is AiCreateUiEvent.OnGenderSelected -> updateGender(event.gender)
            is AiCreateUiEvent.OnNumChanged -> updateNum(event.num)
            is AiCreateUiEvent.OnNsfwChanged -> updateNsfw(event.enabled)
            is AiCreateUiEvent.OnGenerateModeChanged -> updateGenerateMode(event.isKeywordMode)
            is AiCreateUiEvent.OnModelSelected -> updateModel(event.model, event.position)
            is AiCreateUiEvent.OnStyleSelected -> updateStyle(event.style, event.position)
            is AiCreateUiEvent.OnFaceUriChanged -> updateFaceUri(event.uri)
            AiCreateUiEvent.OnSubmit -> handleSubmit()
            AiCreateUiEvent.OnRefresh -> handleRefresh()
            AiCreateUiEvent.OnMore -> handleMore()
            AiCreateUiEvent.OnBack -> handleBack()
            is AiCreateUiEvent.OnAiWriter -> handleAiWriter(event.isNsfw)
        }
    }

    private fun loadAiCreateData() {
        viewModelScope.launchWithLoading {
            val data = taskService.getGenerateData()
            createData?.createData = data
            _createFlow.emit(data)
        }
    }

    private fun updateType(type: Int) {
        viewModelScope.launchSafety {
            createData?.apply {
                this.currentType = type
            }
            _typeFlow.emit(type)
            updateModelAndStyle()
        }
    }

    private fun updateGender(gender: Int) {
        viewModelScope.launchSafety {
            createData?.apply {
                this.currentGender = gender
            }
            _genderFlow.emit(gender)
        }
    }

    private fun updateNum(num: Int) {
        viewModelScope.launchSafety {
            createData?.apply {
                currentNum = num
            }
            _numFlow.emit(num)
        }
    }

    private fun updateNsfw(enabled: Boolean) {
        viewModelScope.launchSafety {
            createData?.apply {
                isNsfwEnabled = enabled
            }
            _updateNsfw.emit(enabled)
        }
    }

    private fun updateGenerateMode(isKeywordMode: Boolean) {
        viewModelScope.launchSafety {
            createData?.apply {
                this.isKeywordMode = isKeywordMode
            }
            _textPictureMode.emit(isKeywordMode)
        }
    }

    private fun updateModel(model: GeneratedModel, position: Int) {
        viewModelScope.launchSafety {
            createData?.apply {
                selectedModel = model
                currentMode = position
            }
            _updateModel.emit(position)
            updateStyle(model.styleVariations.firstOrNull(), 0)
        }
    }

    private fun updateStyle(style: GeneratedModel?, i: Int) {
        viewModelScope.launchSafety {
            createData?.apply {
                selectedStyle = style
                currentStyle = i
            }
            _updateStyle.emit(i)
        }
    }

    private fun updateFaceUri(uri: Uri?) {
        createData?.apply {
            faceUri = uri
        }
    }

    private fun updateModelAndStyle() {
        val models = if (createData?.currentType == 0) {
            createData?.createData?.modelCollections?.realistic ?: emptyList()
        } else {
            createData?.createData?.modelCollections?.animated ?: emptyList()
        }
        updateModel(models.firstOrNull() ?: return, 0)
    }

    private fun handleSubmit() {
        submitTask()
    }

    private fun submitTask() {
        viewModelScope.launchWithLoading {
            val map = buildTaskParams(createData)
            val response = if (createData.faceUri != null) {
                handleImageSubmission(map, createData.faceUri!!)
            } else {
                handleJsonSubmission(map)
            }
            processResponse(response)
        }
    }

    private fun buildTaskParams(state: AiCreateState): Map<String, Any> {
        return mutableMapOf(
            "workflow_type" to when {
                state.faceUri == null -> if (!state.isKeywordMode) "text_to_image" else "pure_text_to_image"
                else -> if (!state.isKeywordMode) "image_to_image" else "pure_image_to_image"
            },
            "age" to (state.age ?: 18),
            "height" to (state.height ?: 168),
            "num" to state.currentNum,
            "is_nsfw" to if (state.isNsfwEnabled && !UserManager.isC()) 1 else 0,
            "gender" to state.currentGender,
            "type" to state.currentType,
            "model" to state.selectedModel?.content.orEmpty(),
            "style" to mapOf(state.selectedStyle?.content to state.selectedStyle?.priority),
        ).apply {
            if (state.isKeywordMode) {
                put("text_input", state.textInput.orEmpty())
            }else {
                putAll(state.imageInput)
            }
        }
    }

    private suspend fun handleImageSubmission(
        map: Map<String, Any>,
        image: Uri
    ): Response<ResponseBody> {
        val queryParams = generateQueryParams(map)
        val finalUrl = buildUrlWithQueryParams("task/post_image_task", queryParams)
        val body = createRequestBodyFromUri(image)?.let {
            MultipartBody.Part.createFormData("file", image.fileName(), it)
        } ?: throw IllegalArgumentException("Image URI is invalid")
        return generateService.generateImage(body, finalUrl)
    }

    private suspend fun handleJsonSubmission(map: Map<String, Any>): Response<ResponseBody> {
        val requestBody = map.toJson().toRequestBody("application/json; charset=utf-8".toMediaType())
        return generateService.generateImage(requestBody)
    }

    private fun generateQueryParams(map: Map<String, Any>): List<String> {
        return map.flatMap { (key, value) ->
            when (value) {
                is Map<*, *> -> value.map { (mapKey, mapValue) -> "$key[$mapKey]=$mapValue" }
                is List<*> -> value.map { item -> "$key[]=$item" }
                else -> listOf("$key=$value")
            }
        }
    }

    private fun buildUrlWithQueryParams(baseUrl: String, queryParams: List<String>): String {
        return "$baseUrl?" + queryParams.joinToString("&")
    }

    private fun processResponse(response: Response<ResponseBody>) {
        val bodyString = response.body()?.string()
        val code = bodyString?.let { JSONObject(it).optInt("code") } ?: -500
        if (response.isSuccessful && code == 1) {
            UserManager.refreshAuth()
            viewModelScope.launch {
                _events.emit(AiCreateEvent.ShowLoadDialog)
            }
        } else {
            viewModelScope.launch {
                _events.emit(AiCreateEvent.ShowToast("提交失败"))
            }
        }
    }

    private fun handleRefresh() {
        viewModelScope.launch {
            _events.emit(
                AiCreateEvent.ShowDialog(
                title = appContext.getString(R.string.clear_create_image),
                message = ""
            ))
        }
    }

    private fun handleMore() {
        viewModelScope.launch {
            _events.emit(AiCreateEvent.NavigateToTask)
        }
    }

    private fun handleBack() {
        // Handle back event
    }

    private fun handleAiWriter(isNsfwEnabled: Boolean) {
        viewModelScope.launchWithLoading {
            val data = taskService.randomGenerateOption(
                mapOf("nsfw" to if (isNsfwEnabled) 1 else 0)
            ).parameterDetails
            createData?.apply {
                randomData = data
            }
            _aiWrite.emit(data)
        }
    }
}